package com.example.wscktest.endpoint;

import net.sf.json.JSONObject;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * javax原生websocket
 * 参考 https://www.cnblogs.com/kiwifly/p/11729304.html
 * https://www.cnblogs.com/yadongliang/p/11459903.html
 *
 * websocket在线测试地址
 * http://www.websocket-test.com/
 * 测试用例
 * ws://127.0.0.1:8080/myWs/admin
 * {
 * "message":"wrwer123123",
 * "To":"admin"
 * }
 *
 * @author lzh
 * @date 2020/8/21 - 17:42
 */
@ServerEndpoint("/myWs/{username}")
@Component
//@ServerEndpoint
//通过这个 spring boot 就可以知道你暴露出去的 ws 应用的路径，
// 有点类似我们经常用的@RequestMapping。
// 比如你的启动端口是8080，而这个注解的值是ws，那我们就可以通过 ws://127.0.0.1:8080/ws 来连接你的应用
public class WsServerEndpoint {

    private static int onlineCount = 0;
    private static Map<String, WsServerEndpoint> clients = new ConcurrentHashMap<String, WsServerEndpoint>();
    private Session session;
    private String username;

    /**
     * 连接成功
     *
     * @param session
     */
    @OnOpen
    //当 websocket 建立连接成功后会触发这个注解修饰的方法，注意它有一个 Session 参数
    public void onOpen(@PathParam("username") String username, Session session) throws IOException {

        this.username = username;
        this.session = session;

        addOnlineCount();
        clients.put(username, this);
        System.out.println("已连接");
    }

    /**
     * 连接关闭
     *
     * @param session
     */
    @OnClose
    //当 websocket 建立的连接断开后会触发这个注解修饰的方法，注意它有一个 Session 参数
    public void onClose(Session session) throws IOException {
        clients.remove(username);
        subOnlineCount();
    }


    /**
     * 接收到消息
     *
     * @param message
     */
    @OnMessage
    //当客户端发送消息到服务端时，会触发这个注解修改的方法，它有一个 String 入参表明客户端传入的值
    public void onMessage(String message) throws IOException {

        JSONObject jsonTo = JSONObject.fromObject(message);
        String mes = (String) jsonTo.get("message");

        if (!jsonTo.get("To").equals("All")){
            sendMessageTo(mes, jsonTo.get("To").toString());
        }else{
            sendMessageAll("给所有人");
        }
    }


    //OnError
    //当 websocket 建立连接时出现异常会触发这个注解修饰的方法，注意它有一个 Session 参数
    @OnError
    public void onError(Throwable throwable, Session session) {
        System.out.println(session.getRequestURI().toString());

        System.out.println(throwable.getMessage());
    }

    //服务端如何发送消息给客户端，服务端发送消息必须通过上面说的 Session 类，通常是在@OnOpen 方法中，
    // 当连接成功后把 session 存入 Map 的 value，key 是与 session 对应的用户标识，
    // 当要发送的时候通过 key 获得 session 再发送，
    // 这里可以通过 session.getBasicRemote_().sendText(_) 来对客户端发送消息。


    public void sendMessageTo(String message, String To) throws IOException {
        for (WsServerEndpoint item : clients.values()) {
            if (item.username.equals(To) )
                item.session.getAsyncRemote().sendText(message);
        }
    }

    public void sendMessageAll(String message) throws IOException {
        for (WsServerEndpoint item : clients.values()) {
            item.session.getAsyncRemote().sendText(message);
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WsServerEndpoint.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WsServerEndpoint.onlineCount--;
    }

    public static synchronized Map<String, WsServerEndpoint> getClients() {
        return clients;
    }
}
